package com.pactera.madp.cp.service.sync.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pactera.madp.admin.api.constant.SyncConstant;
import com.pactera.madp.admin.api.dto.SyncSysDept;
import com.pactera.madp.admin.api.dto.TreeNode;
import com.pactera.madp.admin.api.entity.SysDept;
import com.pactera.madp.admin.api.entity.SysWxDeptRelation;
import com.pactera.madp.admin.api.feign.RemoteSyncSysService;
import com.pactera.madp.common.core.constant.SecurityConstants;
import com.pactera.madp.cp.api.bo.SyncWxOrgBo;
import com.pactera.madp.cp.api.entity.sync.SyncOrgInfoEntity;
import com.pactera.madp.cp.api.entity.sync.SyncWxOrgRelation;
import com.pactera.madp.cp.common.constant.Constants;
import com.pactera.madp.cp.common.util.RedisUtil;
import com.pactera.madp.cp.common.util.WxApiUtils;
import com.pactera.madp.cp.common.util.sync.TreeUtil;
import com.pactera.madp.cp.service.ICorpService;
import com.pactera.madp.cp.service.IWorkEmployeeService;
import com.pactera.madp.cp.service.sync.SyncBatchReplacePartService;
import com.pactera.madp.cp.service.sync.SyncOrgInfoService;
import com.pactera.madp.cp.service.sync.SyncWxOrgRelationService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@AllArgsConstructor
public class SyncBatchReplacePartServiceImpl implements SyncBatchReplacePartService{

    private final ICorpService corpService;
    private final IWorkEmployeeService workEmployeeService;
    private final SyncWxOrgRelationService syncWxOrgRelationService;
    private final SyncOrgInfoService syncOrgInfoService;
    private final RemoteSyncSysService remoteSyncSysService;
    private final RedisTemplate redisTemplate;

    @Override
    public boolean batchSyncDept(String jobId) {
        String nowDate = DateUtil.format(new Date(), Constants.DATE_FORMAT);
        Integer corpId = corpService.list().get(0).getCorpId();

        // 锁定
        String lockKey = RedisUtil.buildKey(Constants.SYNC_ORG_BUSINESS_WX2SYS_LOCK, nowDate);
        boolean isLocked = RedisUtil.getLock(lockKey, 1, Constants.EXPIRE_TIME, TimeUnit.SECONDS);
        if (!isLocked) {
            return false;
        }

        try {
            // 记录回调成功
            setCallbackFlag();

            // 校验企业微信批量任务执行结果
            boolean flag = checkBatchResult(corpId, jobId);
            if (!flag) {
                return false;
            }

            // 保存关联到库
            saveRelationToDB();

            // 同步企业微信到CP
            workEmployeeService.syncDepartment(corpId);

            // 同步本地部门到madp系统
            doBatchSync();
            log.info("开始远程同步企业微信部门到MADP系统");
        } finally {
            redisTemplate.delete(lockKey);
        }
        return true;
    }

    // 批量同步企业微信部门到madp系统
    @SneakyThrows
    private void doBatchSync() {
        // 查询人力资源机构列表
        List<SyncOrgInfoEntity> orgList = syncOrgInfoService.list(Wrappers.<SyncOrgInfoEntity>lambdaQuery()
                .eq(SyncOrgInfoEntity::getDelOrgFlag, Constants.SYNC_DEL_FLAG));
        Map<String, SyncOrgInfoEntity> orgMap = new HashMap<>();
        orgList.forEach(org -> orgMap.put(org.getId(), org));

        // 查询人力资源机构与企业微信部门关联
        List<SyncWxOrgRelation> wxOrgList = syncWxOrgRelationService.list();
        Map<Integer, String> wxOrgMap = new HashMap<>();
        Map<String, Integer> orgWxMap = new HashMap<>();
        wxOrgList.forEach(rel -> {
            wxOrgMap.put(rel.getWxDeptId(), rel.getHrOrgId());
            orgWxMap.put(rel.getHrOrgId(), rel.getWxDeptId());
        });

        // 查询系统部门与企业微信关联
        List<SysWxDeptRelation> sysWxDeptList = remoteSyncSysService.getSysWxRelations(SecurityConstants.FROM_IN).getData();
        Map<Integer,Integer> wxSysMap = new HashMap<>();
        Map<Integer,Integer> sysWxMap = new HashMap<>();
        sysWxDeptList.forEach(rel -> wxSysMap.put(rel.getWxDeptId(), rel.getSysDeptId()));
        sysWxDeptList.forEach(rel -> sysWxMap.put(rel.getSysDeptId(), rel.getWxDeptId()));
        Map<Integer,Integer> wxSysTempMap = new HashMap<>();
        sysWxDeptList.forEach(rel -> wxSysTempMap.put(rel.getWxDeptId(), rel.getSysDeptId()));

        List<SyncSysDept> updateList = new ArrayList<>();
        // 过滤删除
        SyncSysDept syncSysDept = new SyncSysDept();
        for (SyncWxOrgRelation wxOrgRel : wxOrgList) {
            Integer sysDeptId = wxSysMap.remove(wxOrgRel.getWxDeptId());
            // 过滤更新
            if (sysDeptId != null) {
                SyncOrgInfoEntity org = orgMap.get(wxOrgRel.getHrOrgId());
                SyncSysDept ssd = syncSysDept.clone();
                ssd.setSysDeptId(sysDeptId);
                ssd.setDeptName(org.getOrgName());
                ssd.setOrgCode(org.getOrgId());
                if (StrUtil.equals("-1", org.getOrgGroupCode())) {
                    ssd.setSysParentDeptId(0);
                } else {
                    ssd.setSysParentDeptId(wxSysTempMap.get(orgWxMap.get(org.getOrgGroupCode())));
                }
                ssd.setOpt(SyncConstant.UPDATE_OPT);
                updateList.add(ssd);
            }
        }

        // 获取将要删除的系统部门列表
        List<SyncSysDept> delList = new ArrayList<>();
        if (!wxSysMap.isEmpty()) {
            List<Integer> ids = new ArrayList<>();
            wxSysMap.values().forEach(id -> ids.add(id));
            List<SysDept> sysDeptList = remoteSyncSysService.getSysDeptList(ids, SecurityConstants.FROM_IN).getData();
            List<TreeNode> nodes = new ArrayList<>();
            sysDeptList.forEach(dept -> {
                TreeNode node = new TreeNode();
                node.setId(dept.getDeptId());
                node.setParentId(dept.getParentId());
                nodes.add(node);
            });
            List<TreeNode> trees = TreeUtil.buildTree(nodes, "id", "parentId", "children");
            setDelRelation(trees, delList, sysWxMap);

            if (wxSysMap.containsKey(1)) {
                delList.clear();
                log.error("不能删除根部门");
                log.info("企微-机构关联：{}", JSONUtil.toJsonPrettyStr(wxOrgList));
                log.info("企微-系统关联：{}", JSONUtil.toJsonPrettyStr(sysWxDeptList));
            }
        }

        // 缓存企微部门与系统部门的删除关联
        cacheWxSysRelation(delList);

        // 过滤新增
        for (SysWxDeptRelation sysWxRel : sysWxDeptList) {
            wxOrgMap.remove(sysWxRel.getWxDeptId());
        }
        List<SyncOrgInfoEntity> addOrgs = new ArrayList<>();
        wxOrgMap.values().forEach(hrOrgId -> addOrgs.add(orgMap.get(hrOrgId)));

        // 转换业务对象
        List<SyncWxOrgBo> boList = convertEntityToBo(addOrgs);
        // 构建新增树
        boList = TreeUtil.buildTree(boList, "hrOrgId", "orgParentId", "subList");
        // 设置新增关联
        Map<Integer, Integer> _wxSysMap = new HashMap<>();
        sysWxDeptList.forEach(rel -> _wxSysMap.put(rel.getWxDeptId(), rel.getSysDeptId()));
        List<SyncSysDept> newList = setNewRelation(boList, orgWxMap, _wxSysMap);

        List<SyncSysDept> syncList = new ArrayList<>(newList);
        syncList.addAll(updateList);
        syncList.addAll(delList);

        // 设置远程调用
        Map<String, String> param = new HashMap<>();
        param.put("trees", JSONUtil.toJsonStr(syncList));
        // 远程调用
        remoteSyncSysService.onSyncWxDept(param, SecurityConstants.FROM_IN);
    }

    // 记录回调标识
    private void setCallbackFlag() {
        redisTemplate.opsForValue().set(Constants.SYNC_CB_FLAG, "1");
    }

    // 校验企业微信批量任务执行结果
    private boolean checkBatchResult(Integer corpId, String jobId) {
        String partResult = WxApiUtils.getAsyncBatchResult(corpId, jobId);
        if (partResult == null) {
            // 清除关联
            String key = RedisUtil.buildKey(Constants.SYNC_ORG_WX_RELATION, DateUtil.format(new Date(), Constants.DATE_FORMAT));
            redisTemplate.delete(key);
            log.error("校验部门批量任务：" + jobId + "执行失败");
            return false;
        }
//        String reslut = JSONUtil.parseObj(partResult).getStr("result");
//        List<JSONObject> jsonObjs = JSONUtil.toList(JSONUtil.parseArray(reslut), JSONObject.class);
//        for (JSONObject jsonObj : jsonObjs) {
//            if(jsonObj.getInt("action") == 1 && jsonObj.getInt("errcode") == 0) {
//                succDeptList.add(jsonObj.getInt("partyid"));
//            }
//        }
        log.info("校验部门批量任务：执行成功");
        return true;
    }

    // 关联企业微信与机构关联
    private void saveRelationToDB() {
        String key = RedisUtil.buildKey(Constants.SYNC_ORG_WX_RELATION, DateUtil.format(new Date(), Constants.DATE_FORMAT));
        Long size = redisTemplate.opsForList().size(key);
        if (size == null || size == 0) {
            return;
        }
        List<String> list = redisTemplate.opsForList().range(key, 0, size);
        List<SyncWxOrgRelation> relList = new ArrayList<>();
        list.forEach(s -> relList.add(JSONUtil.toBean(s, SyncWxOrgRelation.class)));
        syncWxOrgRelationService.remove(Wrappers.emptyWrapper());
        syncWxOrgRelationService.saveBatch(relList);
        redisTemplate.delete(key);
        log.info("保存企业微信部门与机构关联成功");
    }

    // 转换为业务对象
    private List<SyncWxOrgBo> convertEntityToBo(List<SyncOrgInfoEntity> orgList) {
        SyncWxOrgBo prototype = new SyncWxOrgBo();
        List<SyncWxOrgBo> boList = new ArrayList<>();
        for (SyncOrgInfoEntity org : orgList) {
            SyncWxOrgBo bo = prototype.clone();
            bo.setHrOrgId(org.getId());
            bo.setOrgName(org.getOrgName());
            bo.setOrgParentId(org.getOrgGroupCode());
            bo.setOrgId(org.getOrgId());
            boList.add(bo);
        }
        return boList;
    }

    // 构建机构树
    private List<SyncWxOrgBo> buildTree(List<SyncWxOrgBo> boList) {
        List<SyncWxOrgBo> bos = new ArrayList<>();
        for (SyncWxOrgBo bo : boList) {
            boolean isSub = false;
            for (SyncWxOrgBo comBo : boList) {
                if (StrUtil.equals(bo.getHrOrgId(), comBo.getHrOrgId())) {
                    continue;
                }
                if (StrUtil.equals(bo.getOrgParentId(), comBo.getHrOrgId())) {
                    if (ObjectUtil.isNull(comBo.getSubList())) {
                        comBo.setSubList(new ArrayList<>());
                    }
                    comBo.getSubList().add(bo);
                    isSub = true;
                    break;
                }
            }
            if (!isSub) {
                bos.add(bo);
            }
        }
        return bos;
    }

    // 设置从子到父的顺序
    private void setDelRelation(List<TreeNode> nodes, List<SyncSysDept> ssdList, Map<Integer,Integer> sysWxMap) {
        SyncSysDept ssd = new SyncSysDept();
        nodes.forEach(node -> {
            List<TreeNode> children = node.getChildren();
            if (children != null && children.size() > 0) {
                setDelRelation(children, ssdList, sysWxMap);
            }
            SyncSysDept s = ssd.clone();
            s.setSysDeptId(node.getId());
            s.setWxDeptId(sysWxMap.get(node.getId()));
            s.setOpt(SyncConstant.DELETE_OPT);
            ssdList.add(s);
        });
    }

    // 缓存删除的企业微信与系统部门关联
    private void cacheWxSysRelation(List<SyncSysDept> delList) {
        if (delList.isEmpty()) {
            return;
        }
        List<SysWxDeptRelation> relationList = new ArrayList<>();
        delList.forEach(s -> {
            SysWxDeptRelation re = new SysWxDeptRelation();
            re.setWxDeptId(s.getWxDeptId());
            re.setSysDeptId(s.getSysDeptId());
            relationList.add(re);
        });
        String key = RedisUtil.buildKey(SyncConstant.SYNC_WX_SYS_DEL_LIST, DateUtil.format(new Date(), Constants.DATE_FORMAT));
        redisTemplate.opsForList().leftPushAll(key, relationList);
        log.info("删除的企业微信与系统部门关联：{}", relationList);
    }

    // 设置新增关联
    private List<SyncSysDept> setNewRelation(List<SyncWxOrgBo> boList, Map<String, Integer> orgWxMap, Map<Integer, Integer> wxSysMap) {
        List<SyncSysDept> ssdList = new ArrayList<>();
        SyncSysDept syncSysDept = new SyncSysDept();
        boList.forEach(b -> {
            SyncSysDept ssd = syncSysDept.clone();
            ssd.setDeptName(b.getOrgName());
            ssd.setSysDeptId(wxSysMap.get(orgWxMap.get(b.getHrOrgId())));
            ssd.setSysParentDeptId(wxSysMap.get(orgWxMap.get(b.getOrgParentId())));
            ssd.setWxDeptId(orgWxMap.get(b.getHrOrgId()));
            ssd.setWxParentDeptId(orgWxMap.get(b.getOrgParentId()));
            ssd.setOrgCode(b.getOrgId());
            ssd.setOpt(SyncConstant.NEW_OPT);
            ssdList.add(ssd);
            // 子节点设置
            List<SyncWxOrgBo> subList = b.getSubList();
            if (ObjectUtil.isNotNull(subList)) {
                List<SyncSysDept> subSsdList = setNewRelation(subList, orgWxMap, wxSysMap);
                ssd.setChildren(subSsdList);
            }
        });
        return ssdList;
    }

}
